using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using Lincolnwood.Foundation.Scheduling;
using Rhino.Mocks;

namespace Lincolnwood.Foundation.Scheduling.Tests
{
    [TestClass]
    public class YearlyRecurrencePatternTests
    {
        private MockRepository mockMaker;

        [TestInitialize]
        public void Init()
        {
            mockMaker = new MockRepository();
        }

        [TestMethod]
        public void ExpandRecurringEventWindowBeginBeforeEndBeforeTest()
        {
            string testName = "Test Name";
            string testDesc = "Event used for unit testing yearly recurring events during a window beginning before " +
                "the 1st event occurance and ending before the 1st event occurance";
            DateTime testStart = DateTime.Parse("4/28/1976 8:00 am");
            DateTime testEnd = DateTime.Parse("4/28/1976 9:00 am");

            DateTime testRecurrenceEnd = DateTime.Parse("4/28/2006");

            RecurrableEventDefinition mockEvent = mockMaker.StrictMock<RecurrableEventDefinition>();
            Expect.Call(mockEvent.Name).Return(testName).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.Description).Return(testDesc).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.StartTime).Return(testStart).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.EndTime).Return(testEnd).Repeat.AtLeastOnce();

            mockEvent.Replay();

            YearlyRecurrencePattern testPattern = new YearlyRecurrencePattern(testRecurrenceEnd, 1);

            DateTime expandWindowBegin = DateTime.Parse("4/23/1970");
            DateTime expandWindowEnd = DateTime.Parse("4/29/1975");

            // expand the occurances
            IList<IEventInstance> eventList = testPattern.Expand(mockEvent, expandWindowBegin, expandWindowEnd);

            // make sure that the recurrence got computed correctly
            Assert.AreEqual(0, eventList.Count);
        }

        [TestMethod]
        public void ExpandRecurringEventWindowBeginDuringEndDuringTest()
        {
            string testName = "Test Name";
            string testDesc = "Event used for unit testing yearly recurring events during a windows beginning during the recurring event range " +
                "and ending during the recurring event range.";
            DateTime testStart = DateTime.Parse("4/28/1976 8:00 am");
            DateTime testEnd = DateTime.Parse("4/28/1976 9:00 am");

            DateTime testRecurrenceEnd = DateTime.Parse("4/28/2006");

            RecurrableEventDefinition mockEvent = mockMaker.StrictMock<RecurrableEventDefinition>();
            Expect.Call(mockEvent.Name).Return(testName).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.Description).Return(testDesc).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.StartTime).Return(testStart).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.EndTime).Return(testEnd).Repeat.AtLeastOnce();

            mockEvent.Replay();

            YearlyRecurrencePattern testPattern = new YearlyRecurrencePattern(testRecurrenceEnd, 1);

            // expand the occurances
            IList<IEventInstance> eventList = testPattern.Expand(mockEvent, DateTime.Parse("4/28/1980"), DateTime.Parse("4/28/2000"));

            // make sure that the recurrence got computed correctly
            Assert.AreEqual(21, eventList.Count);
        }

        [TestMethod]
        public void ExpandRecurringEventWindowBeginDuringEndAfterTest()
        {
            string testName = "Test Yearly Recurring Event";
            string testDesc = "Event used for unit testing yearly recurring events during a window beginning during the recurring event range " +
                "and ending after the recurring event ends.";
            DateTime testStart = DateTime.Parse("4/28/1976 8:00 am");
            DateTime testEnd = DateTime.Parse("4/28/1976 9:00 am");

            DateTime testRecurrenceEnd = DateTime.Parse("4/28/2006");

            RecurrableEventDefinition mockEvent = mockMaker.StrictMock<RecurrableEventDefinition>();
            Expect.Call(mockEvent.Name).Return(testName).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.Description).Return(testDesc).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.StartTime).Return(testStart).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.EndTime).Return(testEnd).Repeat.AtLeastOnce();

            mockEvent.Replay();

            YearlyRecurrencePattern testPattern = new YearlyRecurrencePattern(testRecurrenceEnd, 1);

            DateTime expandWindowBegin = DateTime.Parse("4/29/1980");
            DateTime expandWindowEnd = DateTime.Parse("4/29/2010");

            // expand the occurances
            IList<IEventInstance> eventList = testPattern.Expand(mockEvent, expandWindowBegin, expandWindowEnd);
            
            // make sure that the recurrence got computed correctly
            Assert.AreEqual(26, eventList.Count);
        }

        [TestMethod]
        public void ExpandRecurringEventBeginAfterEndAfterWindowTest()
        {
            string testName = "Test Yearly Recurring Event";
            string testDesc = "Event used for unit testing yearly recurring events during a window beginning after the recurring event range " +
                "and also ending after hte recurring event range";
            DateTime testStart = DateTime.Parse("4/28/1976 8:00 am");
            DateTime testEnd = DateTime.Parse("4/28/1976 9:00 am");

            DateTime testRecurrenceEnd = DateTime.Parse("4/28/2006");

            RecurrableEventDefinition mockEvent = mockMaker.StrictMock<RecurrableEventDefinition>();
            Expect.Call(mockEvent.Name).Return(testName).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.Description).Return(testDesc).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.StartTime).Return(testStart).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.EndTime).Return(testEnd).Repeat.AtLeastOnce();

            mockEvent.Replay();

            YearlyRecurrencePattern testPattern = new YearlyRecurrencePattern(testRecurrenceEnd, 1);

            DateTime expandWindowBegin = DateTime.Parse("4/28/2010");
            DateTime expandWindowEnd = DateTime.Parse("4/29/2098");

            // expand the occurances
            IList<IEventInstance> eventList = testPattern.Expand(mockEvent, expandWindowBegin, expandWindowEnd);

            // make sure that the recurrence got computed correctly
            Assert.AreEqual(0, eventList.Count);
        }

        [TestMethod]
        public void ExpandRecurringEventWindowBeginBeforeEndAfterTest()
        {
            string testName = "Test Yearly Recurring Event";
            string testDesc = "Event used for unit testing yearly recurring events during a window beginning before the recurring event range " +
                "and ending after the recurring event range";
            DateTime testStart = DateTime.Parse("4/28/1976 8:00 am");
            DateTime testEnd = DateTime.Parse("4/28/1976 9:00 am");

            DateTime testRecurrenceEnd = DateTime.Parse("4/28/2006");

            RecurrableEventDefinition mockEvent = mockMaker.StrictMock<RecurrableEventDefinition>();
            Expect.Call(mockEvent.Name).Return(testName).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.Description).Return(testDesc).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.StartTime).Return(testStart).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.EndTime).Return(testEnd).Repeat.AtLeastOnce();

            mockEvent.Replay();

            YearlyRecurrencePattern testPattern = new YearlyRecurrencePattern(testRecurrenceEnd, 1);

            DateTime expandWindowBegin = DateTime.Parse("4/28/1950");
            DateTime expandWindowEnd = DateTime.Parse("4/29/2098");


            // expand the occurances
            IList<IEventInstance> eventList = testPattern.Expand(mockEvent, expandWindowBegin, expandWindowEnd);

            // make sure that the recurrence got computed correctly
            Assert.AreEqual(31, eventList.Count);
        }

        [TestMethod]
        public void ExpandRecurringEventWithDeletionException()
        {
            string testName = "Test Yearly Recurring Event";
            string testDesc = "Event used for unit testing yearly recurring events during a window beginning before the recurring event range " +
                "and ending after the recurring event range, also including a deletion exception";
            DateTime testStart = DateTime.Parse("4/28/1976 8:00 am");
            DateTime testEnd = DateTime.Parse("4/28/1976 9:00 am");

            DateTime testRecurrenceEnd = DateTime.Parse("4/28/2006");

            RecurrableEventDefinition mockEvent = mockMaker.StrictMock<RecurrableEventDefinition>();
            Expect.Call(mockEvent.Name).Return(testName).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.Description).Return(testDesc).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.StartTime).Return(testStart).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.EndTime).Return(testEnd).Repeat.AtLeastOnce();

            mockEvent.Replay();

            YearlyRecurrencePattern testPattern = new YearlyRecurrencePattern(testRecurrenceEnd, 1);            

             // create an exception that omits one of the occurances
            testPattern.RemoveInstance(DateTime.Parse("4/28/2005"));

            DateTime expandWindowBegin = DateTime.Parse("4/28/1976");
            DateTime expandWindowEnd = DateTime.Parse("4/28/2006 11:59:59 pm");

            // expand the occurances
            IList<IEventInstance> eventList = testPattern.Expand(mockEvent, expandWindowBegin, expandWindowEnd);

            // make sure that the recurrence got computed correctly
            Assert.AreEqual(30, eventList.Count);
        }

        [TestMethod]
        public void ExpandRecurringEventAndRemoveInstance()
        {
            string testName = "Test Yearly Recurring Event";
            string testDesc = "Event used for unit testing yearly recurring events during a window beginning before the recurring event range " +
                "and ending after the recurring event range, also including a deletion exception";
            DateTime testStart = DateTime.Parse("4/28/1976 8:00 am");
            DateTime testEnd = DateTime.Parse("4/28/1976 9:00 am");

            DateTime testRecurrenceEnd = DateTime.Parse("4/28/2006");

            RecurrableEventDefinition mockEvent = mockMaker.StrictMock<RecurrableEventDefinition>();
            Expect.Call(mockEvent.Name).Return(testName).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.Description).Return(testDesc).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.StartTime).Return(testStart).Repeat.AtLeastOnce();
            Expect.Call(mockEvent.EndTime).Return(testEnd).Repeat.AtLeastOnce();

            mockEvent.Replay();

            YearlyRecurrencePattern testPattern = new YearlyRecurrencePattern(testRecurrenceEnd, 1); 

            // omit one of the occurances
            var eventException = testPattern.RemoveInstance(DateTime.Parse("4/28/2000"));

            DateTime expandWindowBegin = DateTime.Parse("4/28/1976");
            DateTime expandWindowEnd = DateTime.Parse("4/28/2006 11:59:59 pm");

            // expand the occurances
            IList<IEventInstance> eventList = testPattern.Expand(mockEvent, expandWindowBegin, expandWindowEnd);

            // make sure that the recurrence got computed correctly
            Assert.AreEqual(30, eventList.Count);

            // make sure our event exception is not in the collection
            var n = (from i in eventList where i.StartTime == DateTime.Parse("4/28/2000 8:00 am") select i).Count<IEventInstance>();

            Assert.AreEqual(0, n);
        }

    }
}
